/* =============================================================
 * port_picker.js v1.1.0
 * =============================================================
 * Original written by Ysy
 * =============================================================
 * Date 03/06/2020
 * ============================================================ */

(function (factory) {
    "use strict";
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    } else {
        factory(jQuery);
    }
}(function ($) {

    let CityPicker = function (element, options) {
        this.options = $.extend({}, $.fn.cityPicker.defaults, options);
        this.source = this.options.source;
        this.$element = $(element);
        this.$container = $(this.options.container);
        this.$title = $(this.options.title);
        this.$tab = $(this.options.tab);
        this.$main = $(this.options.main);

        this.afterSelect = this.options.afterSelect;

        this.list = [];
        this.area = {};
        this.selected = {};
        this.tab = "";

        this.inputList = [];
        this.value = "";

        this.$inputMain = $(this.options.inputMain);
        this.$inputMenu = $(this.options.inputMenu);
        this.shown = this.options.shown;
        this.focus = this.options.focus;
        this.mouseEnter = this.options.mouseEnter;

        this.listen();
    };

    CityPicker.prototype = {

        constructor: CityPicker,

        render: function () {// 渲染
            this.$container.append(this.$title);// 标题
            this.$container.append(this.$tab);// 导航
            this.$container.append(this.$main);// 主体

            this.$title.find("span").text(this.options.titleContent);

            $("body").append(this.$container);

            if ($.isFunction(this.source)) {
                this.source($.proxy(this.process, this));
            } else if (this.source) {
                this.list = this.source;
                $.each(this.list, (index, value) => {
                    $.each(value.areaList, (idx, val) => {
                        let obj = {};
                        obj.id = val.code;
                        obj.text = val.name;
                        obj.parent = value.code;
                        this.inputList.push(obj);
                    });
                });
                this.displayText();
            }

            this.show();
        },

        flexSet: function () {
            // flex 布局 填满元素
            let num = this.$main.find("ul li").length % 6;
            for (let i = 0; i < 6 - num; i++) {
                this.$main.find("ul").append("<li></li>");
            }
        },

        displayText: function () {
            if (this.isEmptyString(this.tab)) {
                this.tab = this.list[0].code;

                let tab = "";
                $.each(this.list, (index, value) => {
                    tab += "<li data-code='" + value.code + "'>" + value.name + "</li>";
                });
                this.$tab.find("ul").html(tab);

                // 默认选中第一个
                this.$tab.find("ul li").eq(0).addClass("selected");
            }

            this.area = this.list.find((x) => {
                return x.code == this.tab;
            });

            let html = "";

            $.each(this.area.areaList, (index, value) => {
                html += "<li data-code='" + value.code + "'>" + value.name + "</li>";
            });

            this.$main.find("ul").html(html);

            // 数据回显
            if (Object.keys(this.selected).length !== 0) {
                $.each(this.$main.find("ul li"), (index, value) => {
                    if ($(value).data("code") === this.selected.data("code")) {
                        $(value).addClass("selected");
                    }
                });
            }

            this.flexSet();
        },

        stopEvent: function (e) {
            e.stopPropagation();
            e.preventDefault();
        },

        init: function (e) {
            this.stopEvent(e);
            this.render();
        },

        listen: function () {
            this.$element
                .on("click", $.proxy(this.init, this))
                .on("input", $.proxy(this.input, this))
                .on("blur", $.proxy(this.blur, this))
                .on("keyup", $.proxy(this.keyup, this))
                .on("keypress", $.proxy(this.keypress, this));


            this.$container
                .on("click", $.proxy(this.stopEvent, this));

            this.$main
                .on("click", "ul li", $.proxy(this.select, this));

            this.$tab
                .on("click", "ul li", $.proxy(this.tabSwitch, this));

            this.$inputMenu.on("click", "li", $.proxy(this.click, this))
                .on("mouseenter", "li", $.proxy(this.mouseenter, this))
                .on("mouseleave", $.proxy(this.mouseleave, this));

            $(document).on("click", (e) => {
                this.hide();
            });
        },

        tabSwitch: function (e) {
            this.tab = $(e.target).data("code");
            this.$tab.find("ul li").removeClass("selected");
            $(e.target).addClass("selected");
            this.displayText();
        },

        select: function (e) {
            let object = {
                code: $(e.target).data("code"),
                name: $(e.target).text(),
            };

            this.selected = $(e.target);
            this.hide();
            this.afterSelect(this.area, object);
        },

        // 字符串非空判定
        isEmptyString: function (str) {
            let boolean = true;

            // 正则表达式用于判斷字符串是否全部由空格或换行符组成
            let reg = /^\s*$/;
            if (str && str !== undefined && str != null && str !== "" && !reg.test(str)) boolean = false;

            return boolean;
        },

        show: function () {
            this.$container.fadeIn(500);
        },

        hide: function () {
            this.$container.fadeOut(500);
            this.destroy();
        },

        process: function (data) {
            this.list = data;
            $.each(this.list, (index, value) => {
                $.each(value.areaList, (idx, val) => {
                    let obj = {};
                    obj.id = val.code;
                    obj.text = val.name;
                    obj.parent = value.code;
                    this.inputList.push(obj);
                });
            });
            this.displayText();
        },

        destroy: function () {
            this.$container.detach();
        },

        // input 调用input-select
        input: function (e) {
            this.shown = true;
            this.hide();
            this.inputRender();
        },

        inputRender: function () {// 渲染
            if (this.inputList.length === 0) {
                this.inputHide();
                return;
            }

            let items = $(this.inputList).map((index, item) => {

                index = $(this.options.inputItem);
                this.displayInputText(index, item);

                return index[0];
            });
            $(items[0]).addClass("active");
            this.$inputMenu.html(items);

            this.$inputMain.append(this.$inputMenu);
            this.$element.after(this.$inputMain);

            this.inputShow();
        },

        displayInputText: function (ele, data) {// 显示文本
            ele.data("id", data.id);
            ele.data("text", data.text);
            ele.html(data.text + data.id);
            // this.afterDisplayText(ele, data);
        },

        inputShow: function () {
            if (!this.shown) return;

            let width = this.options.width === "" ? this.$element[0].offsetWidth : this.options.width;
            let height = this.$element[0].offsetHeight;
            let left = this.$element.position().left;
            let top = this.$element.position().top + height - 5;
            this.$inputMain.css({"width": width, "top": top, "left": left,});
            this.$inputMain.fadeIn(300);
        },

        inputHide: function () {
            this.shown = false;
            this.$inputMain.fadeOut(0);
            this.inputDestroy();
        },

        blur: function () {
            if (this.mouseEntered) return;
            this.inputHide();
        },

        keyup: function (e) {
            // if (this.suppressKeyPressRepeat) return;
            this.move(e);
        },

        keypress: function (e) {
            if (!this.shown) return;

            switch (e.keyCode) {
                case 9: // tab
                case 13: // enter
                    e.preventDefault();
                    this.inputSelect();
                    this.inputHide();
                    break;
                case 27: // escape
                case 38: // up arrow
                case 40: // down arrow
            }
        },

        click: function (e) {
            e.preventDefault();
            this.inputSelect();
            this.inputHide();
        },

        mouseenter: function (e) {
            this.mouseEntered = true;
            this.$inputMenu.find(".active").removeClass("active");
            $(e.currentTarget).addClass("active");
        },

        mouseleave: function () {
            this.mouseEntered = false;
        },

        inputSelect: function () {
            let value = this.$inputMenu.find(".active");
            this.$element.val(value.data("text"));
            // this.afterSelect(value.data("id"), value.data("text"), this.$element);
        },

        move: function (e) {
            if (!this.shown) return;

            switch (e.keyCode) {
                case 9: // tab
                case 13: // enter
                case 27: // escape
                    e.preventDefault();
                    break;

                case 38: // up arrow
                    // with the shiftKey (this is actually the left parenthesis)
                    if (e.shiftKey) return;
                    e.preventDefault();
                    this.prev();
                    break;

                case 40: // down arrow
                    // with the shiftKey (this is actually the right parenthesis)
                    if (e.shiftKey) return;
                    e.preventDefault();
                    this.next();
                    break;
            }
        },

        prev: function () {
            let active = this.$inputMenu.find(".active").removeClass("active");
            active = active.prev();

            if (!active.length)
                active = this.$inputMenu.find("li").last();

            this.scroll(active);
            active.addClass("active");
        },

        next: function () {
            let active = this.$inputMenu.find(".active").removeClass("active");
            active = active.next();

            if (!active.length) {
                active = $(this.$inputMenu.find("li").first());
            }

            this.scroll(active);
            active.addClass("active");
        },

        scroll: function (ele) {
            this.$inputMain.animate({scrollTop: this.$inputMain.scrollTop() + ele.offset().top - this.$inputMain.offset().top}, 150);
        },

        inputDestroy: function () {
            this.$element.parent().find("div." + this.$inputMain.prop("class")).detach();
        },

    };

    let old = $.fn.cityPicker;

    $.fn.cityPicker = function (options) {
        return new CityPicker(this, options);
    };

    $.fn.cityPicker.defaults = {
        container: "<div class='port_picker_container'></div>",
        title: "  <div class='title'>" +
        "            <span></span>" +
        "        </div>",
        tab: "<div class='tab'>" +
        "       <ul></ul>" +
        "     </div>",
        main: "<div class='main'>" +
        "           <ul></ul>" +
        "       </div>",
        titleContent: "热门港口 (可直接输入港口或港口拼音)",
        afterSelect: $.noop(),
        inputMain: "<div class='input-select-ysy'></div>",
        inputMenu: "<ul></ul>",
        inputItem: "<li></li>",
        shown: false,
        focused: false,
        mouseEntered: false,
        width: "",
        afterInputSelect: $.noop,
        afterDisplayInputText: $.noop,
    };

    $.fn.cityPicker.Constructor = CityPicker;

    $.fn.cityPicker.noConflict = function () {
        $.fn.cityPicker = old;
        return this;
    };
}));